const jsnes = require('jsnes');
const fs = require('fs');
const { createCanvas } = require('canvas');
const GIFEncoder = require('gifencoder');
const config = require('./config');

// 定义常量
const NES_WIDTH = 256;
const NES_HEIGHT = 240;
const NES_FRAMEBUFFER_SIZE = NES_WIDTH * NES_HEIGHT;

// 从配置文件加载设置
const DISPLAY_CONFIGS = config.DISPLAY_CONFIGS;
const DISPLAY_CONFIG = DISPLAY_CONFIGS[config.CURRENT_CONFIG];
const SCREEN_WIDTH = DISPLAY_CONFIG.width;
const SCREEN_HEIGHT = DISPLAY_CONFIG.height;
const SCALE_FACTOR = DISPLAY_CONFIG.scale;

console.log('=== NES游戏模拟器 - 高分辨率版本 ===');
console.log(`当前配置: ${Object.keys(DISPLAY_CONFIGS).find(key => DISPLAY_CONFIGS[key] === DISPLAY_CONFIG)}`);
console.log(`输出分辨率: ${SCREEN_WIDTH}x${SCREEN_HEIGHT}`);
console.log(`放大倍数: ${SCALE_FACTOR}x`);
console.log(`插值算法: ${config.USE_NEAREST_NEIGHBOR ? '最近邻插值(保持像素艺术风格)' : '双线性插值(平滑效果)'}`);
console.log('按 Ctrl+C 停止录制并生成GIF文件');
console.log('=====================================');

// 图像放大算法
function nearestNeighborUpscale(sourceData, sourceWidth, sourceHeight, targetWidth, targetHeight) {
  const targetData = new Uint8ClampedArray(targetWidth * targetHeight * 4);
  const scaleX = sourceWidth / targetWidth;
  const scaleY = sourceHeight / targetHeight;
  
  for (let y = 0; y < targetHeight; y++) {
    for (let x = 0; x < targetWidth; x++) {
      const sourceX = Math.floor(x * scaleX);
      const sourceY = Math.floor(y * scaleY);
      const sourceIndex = (sourceY * sourceWidth + sourceX) * 4;
      const targetIndex = (y * targetWidth + x) * 4;
      
      targetData[targetIndex] = sourceData[sourceIndex];     // R
      targetData[targetIndex + 1] = sourceData[sourceIndex + 1]; // G
      targetData[targetIndex + 2] = sourceData[sourceIndex + 2]; // B
      targetData[targetIndex + 3] = sourceData[sourceIndex + 3]; // A
    }
  }
  
  return targetData;
}

// 双线性插值放大算法（更平滑但可能模糊像素艺术）
function bilinearUpscale(sourceData, sourceWidth, sourceHeight, targetWidth, targetHeight) {
  const targetData = new Uint8ClampedArray(targetWidth * targetHeight * 4);
  const scaleX = (sourceWidth - 1) / targetWidth;
  const scaleY = (sourceHeight - 1) / targetHeight;
  
  for (let y = 0; y < targetHeight; y++) {
    for (let x = 0; x < targetWidth; x++) {
      const gx = x * scaleX;
      const gy = y * scaleY;
      const gxi = Math.floor(gx);
      const gyi = Math.floor(gy);
      const gxw = gx - gxi;
      const gyw = gy - gyi;
      
      const c00 = (gyi * sourceWidth + gxi) * 4;
      const c10 = (gyi * sourceWidth + Math.min(gxi + 1, sourceWidth - 1)) * 4;
      const c01 = (Math.min(gyi + 1, sourceHeight - 1) * sourceWidth + gxi) * 4;
      const c11 = (Math.min(gyi + 1, sourceHeight - 1) * sourceWidth + Math.min(gxi + 1, sourceWidth - 1)) * 4;
      
      const targetIndex = (y * targetWidth + x) * 4;
      
      for (let i = 0; i < 4; i++) {
        const c0 = sourceData[c00 + i] * (1 - gxw) + sourceData[c10 + i] * gxw;
        const c1 = sourceData[c01 + i] * (1 - gxw) + sourceData[c11 + i] * gxw;
        targetData[targetIndex + i] = Math.round(c0 * (1 - gyw) + c1 * gyw);
      }
    }
  }
  
  return targetData;
}

// 创建Canvas和GIFEncoder
const canvas = createCanvas(SCREEN_WIDTH, SCREEN_HEIGHT);
const ctx = canvas.getContext('2d');
const encoder = new GIFEncoder(SCREEN_WIDTH, SCREEN_HEIGHT);

// 设置GIFEncoder参数
encoder.setRepeat(config.GIF_SETTINGS.repeat);
encoder.setDelay(config.GIF_SETTINGS.delay);
encoder.setQuality(config.GIF_SETTINGS.quality);

// 分配帧缓冲区数组
let nes_framebuffer_u8, nes_framebuffer_u32;
let nes_image = ctx.getImageData(0, 0, NES_WIDTH, NES_HEIGHT);
let nes_buffer = new ArrayBuffer(nes_image.data.length);
nes_framebuffer_u8 = new Uint8ClampedArray(nes_buffer);
nes_framebuffer_u32 = new Uint32Array(nes_buffer);

// 创建高分辨率图像数据
let display_image = ctx.getImageData(0, 0, SCREEN_WIDTH, SCREEN_HEIGHT);

// 初始化画布背景
ctx.fillStyle = "black";
ctx.fillRect(0, 0, SCREEN_WIDTH, SCREEN_HEIGHT);

// 配置参数
const USE_NEAREST_NEIGHBOR = config.USE_NEAREST_NEIGHBOR;

// 初始化NES模拟器
const nes = new jsnes.NES({
  onFrame: function(framebuffer_24) {
    console.log('onFrame enter:');
    
    // 将NES帧缓冲区数据转换为Uint32Array
    for (let i = 0; i < NES_FRAMEBUFFER_SIZE; i++) {
      nes_framebuffer_u32[i] = 0xFF000000 | framebuffer_24[i];
    }

    // 设置NES原始图像数据
    nes_image.data.set(nes_framebuffer_u8);
    
    // 使用选择的算法进行图像放大
    let upscaledData;
    if (USE_NEAREST_NEIGHBOR) {
      upscaledData = nearestNeighborUpscale(
        nes_framebuffer_u8, 
        NES_WIDTH, 
        NES_HEIGHT, 
        SCREEN_WIDTH, 
        SCREEN_HEIGHT
      );
    } else {
      upscaledData = bilinearUpscale(
        nes_framebuffer_u8, 
        NES_WIDTH, 
        NES_HEIGHT, 
        SCREEN_WIDTH, 
        SCREEN_HEIGHT
      );
    }
    
    // 设置高分辨率图像数据
    display_image.data.set(upscaledData);
    ctx.putImageData(display_image, 0, 0);

    // 添加当前帧到GIF
    encoder.addFrame(ctx);
  },
  onAudioSample: function(left, right) {
    // 处理音频样本，这里可以添加音频播放逻辑
    // console.log('onAudioSample:');
  }
});

// 读取ROM文件
try {
  const romData = fs.readFileSync('test1.nes', { encoding: 'binary' });
  nes.loadROM(romData);
} catch (error) {
  console.error('读取ROM文件失败:', error);
  process.exit(1);
}

// 启动GIF编码
encoder.start();

// 运行NES帧
const frameTime = 1000 / 60; // 60 FPS 意味着每帧 16.67 毫秒
function runFrame() {
  nes.frame();
  // 可以在这里处理输入设备
  // nes.buttonDown(1, jsnes.Controller.BUTTON_A);
  // nes.frame();
  // nes.buttonUp(1, jsnes.Controller.BUTTON_A);
  // nes.frame();
}

setInterval(runFrame, frameTime);

// 保持应用程序活动状态
process.stdin.resume();

// 处理 Ctrl+C 退出
process.on('SIGINT', function() {
  console.log('Exiting...');
  encoder.finish();
  const buffer = encoder.out.getData();
  
  // 根据配置生成文件名
  const configName = Object.keys(DISPLAY_CONFIGS).find(key => 
    DISPLAY_CONFIGS[key] === DISPLAY_CONFIG
  );
  const algorithmName = USE_NEAREST_NEIGHBOR ? 'nearest' : 'bilinear';
  const filename = `nes_${configName}_${algorithmName}_${SCREEN_WIDTH}x${SCREEN_HEIGHT}.gif`;
  
  fs.writeFileSync(filename, buffer);
  console.log(`高分辨率动态GIF已生成: ${filename}`);
  console.log(`分辨率: ${SCREEN_WIDTH}x${SCREEN_HEIGHT}`);
  console.log(`放大倍数: ${SCALE_FACTOR}x`);
  console.log(`插值算法: ${USE_NEAREST_NEIGHBOR ? '最近邻插值(像素艺术风格)' : '双线性插值(平滑)'}`);
  process.exit();
});
